package top.mschen.blog.common.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Component
@Aspect
public class AspectrRequestLog {

    private static  final Logger LOGGER = LoggerFactory.getLogger(AspectrRequestLog.class);
    ThreadLocal<Long>  startTime = new ThreadLocal<Long>();

    /**
     * 指定切点
     * 匹配 com.example.demo.controller包及其子包下的所有类的所有方法
     */
    @Pointcut("execution(public * top.mschen.blog.controller.*.*(..))")
    public void webLog(){
    }

    /**
     * 前置通知，方法调用前被调用
     * @param joinPoint
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint){
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        startTime.set(System.currentTimeMillis());
        //开始时间
        LOGGER.info("        before time = {}",startTime.get());
        // url
        LOGGER.info("                url = {}", request.getRequestURL());
        // method
        LOGGER.info("             method = {}", request.getMethod());
        // ip
        LOGGER.info("                 ip = {}", request.getRemoteAddr());
        // 类.方法
        LOGGER.info("       class.method = {}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "()");
        // 请求参数
        LOGGER.info("               args = {}", joinPoint.getArgs());
    }

    /**
     * 处理完请求返回内容
     * @param ret
     * @throws Throwable
     */
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
        LOGGER.info("       after returning = {}", ret == null ? "" : ret.toString());
    }

    /**
     * 后置异常通知
     * @param jp
     */
    @AfterThrowing("webLog()")
    public void throwss(JoinPoint jp){
        LOGGER.info("方法异常时执行.....{}",jp.getSignature().getDeclaringTypeName()+"."+jp.getSignature().getName()+"()");
    }

    /**
     * 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
     * @param jp
     */
    @After("webLog()")
    public void after(JoinPoint jp){
        // 请求参数
        long afterTime = System.currentTimeMillis();
        //结束时间
        LOGGER.info("         after time = {}", afterTime);
        //耗时
        LOGGER.info("           耗时(毫秒)： {}",(afterTime-startTime.get()));
    }

    /**
     * 环绕通知,环绕增强，相当于MethodInterceptor
     * @param pjp
     * @return
     */
//    @Around("webLog()")
//    public Object arround(ProceedingJoinPoint pjp) {
//        try {
//            Object o =  pjp.proceed();
//            return o;
//        } catch (Throwable e) {
//            e.printStackTrace();
//            return null;
//        }
//    }

}
